package com.dylan.历史.多线程.并发编程的艺术;

import com.dylan.历史.util.LogUtil;
import com.dylan.历史.util.SleepUtils;

import java.util.concurrent.*;

/**
 * Created by Dylan on 2018/9/19.
 */
public class 线程池 {

    /**
     * 创建线程池参数说明：
     * corePoolSize：核心线程数，一直存活的线程数，不受keepAliveTime的限制
     * maximumPoolSize：最大线程数，线程池容纳的最大线程数
     * keepAliveTime 和 unit：空闲的非核心线程存活时长
     * workQueue：任务队列，且是阻塞队列，队列容量固定不能扩展
     *
     * 提交一个新任务到线程池时(ThreadPoolExecutor执行execute)，线程池的处理流程如下：
     * 1）如果当前运行的线程少于corePoolSize，则创建新线程来执行任务。
     *    即使有空闲的线程，也会创建新线程。
     * 2）如果运行的线程等于或多于corePoolSize，则将任务加入BlockingQueue。
     * 3）如果无法将任务加入BlockingQueue（队列已满），则创建新的线程来处理任务。
     * 4）如果创建新线程将是当前运行的线程超出maximumPoolSize，任务将被拒绝，并调用
     *    RejectedExecutionHandler.rejectedExecution()方法。
     */
    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(
                5, 10, 2, TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(10),
                (r, executor) -> LogUtil.info("任务 " + ((Runner) r).getNum() + " 提交失败...."));
        for (int i = 0; i < 35; i++) {
            if (i < 10) {
                SleepUtils.milliseconds(500);
            } else {
//                SleepUtils.milliseconds(50);
            }
            executorService.execute(new Runner(i, 1000));
        }
        executorService.shutdown();
    }

    static class Runner implements Runnable {
        private int num;
        private long milliseconds;

        public Runner(int num, long milliseconds) {
            this.num = num;
            this.milliseconds = milliseconds;
        }

        @Override
        public void run() {
            LogUtil.info("任务 " + num + " 开始运行");
            SleepUtils.milliseconds(milliseconds);
//            LogUtil.info("-------- 任务 " + num + " 结束运行");
        }

        public int getNum() {
            return num;
        }
    }
}
